#include "bsp.h"

#define IO_H  TRUE
#define IO_L  FALSE

/***************************************************************************************************
 * @fn      bsp_i2c_start
 *
 * @brief   i2c起始 
 *
 * @param   i2c 软件i2c底层操作结构体
 *
 * @return  无
 */
void bsp_i2c_start(soft_i2c_t * i2c)
{
    /* 设置为输出模式 */
    i2c->set_sda_mode_out(TRUE);
    
    i2c->set_scl(IO_H);
    i2c->set_sda(IO_H);
    i2c->delay();
    i2c->set_sda(IO_L);
    i2c->delay();
    i2c->set_scl(IO_L);
}

/***************************************************************************************************
 * @fn      bsp_i2c_stop
 *
 * @brief   i2c停止
 *
 * @param   i2c 软件i2c底层操作结构体
 *
 * @return  无
 */
void bsp_i2c_stop(soft_i2c_t * i2c)
{
    /* 设置为输出模式 */
    i2c->set_sda_mode_out(TRUE);
    
    i2c->set_scl(IO_L);
    i2c->set_sda(IO_L);
    i2c->delay();
    i2c->set_scl(IO_H);
    i2c->set_sda(IO_H);
    i2c->delay();
}

/***************************************************************************************************
 * @fn      bsp_i2c_write_byte
 *
 * @brief   写一个字节数据
 *
 * @param   i2c 软件i2c底层操作结构体
 * @param   byte 写入的数据
 *
 * @return  无
 */
void bsp_i2c_write_byte(soft_i2c_t * i2c, uint8_t byte)
{
    uint8_t i;  

    /* 设置为输出模式 */
    i2c->set_sda_mode_out(TRUE);    

    for(i = 0; i < 8; i++)
    {   
        if((byte & 0x80) >> 7)
            i2c->set_sda(IO_H);
        else
            i2c->set_sda(IO_L);
        
        byte = byte << 1;
				
        i2c->delay();
        i2c->set_scl(IO_H);
        i2c->delay(); 
        i2c->set_scl(IO_L);
        i2c->delay();
    }    
}

/***************************************************************************************************
 * @fn      bsp_i2c_ack
 *
 * @brief   i2c应答
 *
 * @param   i2c 软件i2c底层操作结构体
 *
 * @return  无
 */
void bsp_i2c_ack(soft_i2c_t * i2c)
{
    /* 设置为输出模式 */
    i2c->set_sda_mode_out(TRUE);
    
    i2c->set_scl(IO_L);
    i2c->set_sda(IO_L);
    i2c->delay();
    i2c->set_scl(IO_H);
    i2c->delay();
    i2c->set_scl(IO_L);
    i2c->delay();
}

/***************************************************************************************************
 * @fn      bsp_i2c_nack
 *
 * @brief   i2c非应答
 *
 * @param   i2c 软件i2c底层操作结构体
 *
 * @return  无
 */
void bsp_i2c_nack(soft_i2c_t * i2c)
{
    /* 设置为输出模式 */
    i2c->set_sda_mode_out(TRUE);
    
    i2c->set_scl(IO_L);
    i2c->set_sda(IO_H);
    i2c->delay();
    i2c->set_scl(IO_H);
    i2c->delay();
    i2c->set_scl(IO_L);
    i2c->delay();
}

/***************************************************************************************************
 * @fn      bsp_i2c_wait_ack
 *
 * @brief   等待，检测应答信号
 *
 * @param   i2c 软件i2c底层操作结构体
 *
 * @return  0 正常应答，1 应答超时
 */
uint8_t bsp_i2c_wait_ack(soft_i2c_t * i2c)
{
    uint8_t ack = 0;
    uint16_t erro_time = 0;
   
    /* 设置为输出模式 */
    i2c->set_sda_mode_out(TRUE); 
    i2c->set_sda(IO_H);
    i2c->delay();
    
    /* 设置为输入模式 */
    i2c->set_sda_mode_out(FALSE);
    i2c->set_scl(IO_H);
    i2c->delay(); 

    while(i2c->get_sda())
    {
        erro_time++;
        if(erro_time > 200)
        {
            ack = 1;
            bsp_i2c_stop(i2c);
            return ack;
        }
    }
    i2c->set_scl(IO_L);
    i2c->delay();

    return ack;
}

/***************************************************************************************************
 * @fn      bsp_i2c_read_byte
 *
 * @brief   读一个字节数据
 *
 * @param   i2c 软件i2c底层操作结构体
 *
 * @return  读取到的数据
 */
uint8_t bsp_i2c_read_byte(soft_i2c_t * i2c)
{
    uint8_t i;
    uint8_t byte = 0;
    
    /* 设置为输入模式 */
    i2c->set_sda_mode_out(FALSE);

    for(i = 0; i < 8; i++ )
    {
        byte = byte << 1;
        
        i2c->set_scl(IO_H);
        i2c->delay();
        i2c->set_scl(IO_L);
        
        if(i2c->get_sda())
        {
            byte++; 
        }
        
        i2c->delay();
    }

    return byte;
}


/***************************************************************************************************
 * @fn      i2c_check_device
 *
 * @brief   检查i2c设备是否正常
 *
 * @param   i2c 软件i2c底层操作结构体
 *
 * @return  正常返回TRUE，否则返回FALSE
 */
BOOL i2c_check_device(soft_i2c_t * i2c)
{
    uint8_t ack;
    
    /* 设置为输入模式 */
    i2c->set_sda_mode_out(FALSE);

    if (i2c->get_sda())
    {
        bsp_i2c_start(i2c);  /* 发动起始信号 */

        /* 写器件地址 */
        bsp_i2c_write_byte(i2c, (i2c->dev_addr << 1));
        ack = bsp_i2c_wait_ack(i2c);
        if (0 == ack)
        {
            bsp_i2c_stop(i2c);
            return TRUE;
        }
        else
        {
            bsp_i2c_stop(i2c);
        }
    }

    return FALSE;
}




